﻿#include "ntripdeal.h"
#include "log/logger.h"
#include "common/mystring.h"
#include "common/socket_datasource.h"
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cctype>
#include <memory.h>
#include <sstream>

#ifdef _LINUX_
#elif _WIN32
#include <direct.h>
#else
#endif

 typedef unsigned char     uint8;
 typedef unsigned long    uint32;
 
 static uint8 alphabet_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 static uint8 reverse_map[] =
 {
      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
      255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
      15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
      255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
      41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
 };
 
 uint32 base64_encode(const uint8 *text, uint32 text_len, uint8 *encode)
 {
     uint32 i, j;
     for (i = 0, j = 0; i+3 <= text_len; i+=3)
     {
         encode[j++] = alphabet_map[text[i]>>2];                             //取出第一个字符的前6位并找出对应的结果字符
         encode[j++] = alphabet_map[((text[i]<<4)&0x30)|(text[i+1]>>4)];     //将第一个字符的后2位与第二个字符的前4位进行组合并找到对应的结果字符
         encode[j++] = alphabet_map[((text[i+1]<<2)&0x3c)|(text[i+2]>>6)];   //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符
         encode[j++] = alphabet_map[text[i+2]&0x3f];                         //取出第三个字符的后6位并找出结果字符
     }
 
     if (i < text_len)
     {
         uint32 tail = text_len - i;
         if (tail == 1)
         {
             encode[j++] = alphabet_map[text[i]>>2];
             encode[j++] = alphabet_map[(text[i]<<4)&0x30];
             encode[j++] = '=';
             encode[j++] = '=';
         }
         else //tail==2
         {
             encode[j++] = alphabet_map[text[i]>>2];
             encode[j++] = alphabet_map[((text[i]<<4)&0x30)|(text[i+1]>>4)];
             encode[j++] = alphabet_map[(text[i+1]<<2)&0x3c];
             encode[j++] = '=';
         }
     }
     return j;
 }
 
 uint32 base64_decode(const uint8 *code, uint32 code_len, uint8 *plain)
 {
     //assert((code_len&0x03) == 0);  //如果它的条件返回错误，则终止程序执行。4的倍数。
 
     uint32 i, j = 0;
     uint8 quad[4];
     for (i = 0; i < code_len; i+=4)
     {
         for (uint32 k = 0; k < 4; k++)
         {
             quad[k] = reverse_map[code[i+k]];//分组，每组四个分别依次转换为base64表内的十进制数
         }
 
         //assert(quad[0]<64 && quad[1]<64);
 
         plain[j++] = (quad[0]<<2)|(quad[1]>>4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的前2位进行组合
 
         if (quad[2] >= 64)
             break;
         else if (quad[3] >= 64)
         {
             plain[j++] = (quad[1]<<4)|(quad[2]>>2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应base64表的十进制数的前4位进行组合
             break;
         }
         else
         {
             plain[j++] = (quad[1]<<4)|(quad[2]>>2);
             plain[j++] = (quad[2]<<6)|quad[3];//取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合
         }
     }
     return j;
 }
 std::string  NtripDeal::MostRecentGGA = "";
 NtripDeal::NtripDeal() :mGpsDeal(NULL), NTRIPThread(NULL),
	 NTRIPIsConnected(false), StartNTRIPThreadIn(0), NTRIPConnectionAttempt(1),
	 NTRIPStreamRequiresGGA(false), NTRIPUseManualGGA(false),
	 NTRIPProtocol(1), NTRIPPort(0), NTRIPManualLat(41), NTRIPManualLon(-91),
	 NTRIPByteCount(0), mSerialPort(NULL), mCallBack(NULL), NTRIPCaster(""), NTRIPUsername(""),
	 NTRIPPassword(""), NTRIPMountPoint(""), GPSThread(NULL),
	mSettingsfile(""),PreferredMountPoint("")
{
	 initDefalut();
}

 void NtripDeal::initDefalut() 
 {
	 NTRIPShouldBeConnected = true;
	 mGpsDeal = new GPSDeal();
	 NTRIPStreamArray.reserve(2);
 }

 void NtripDeal::initConnect(const std::string &path, int type, int source) 
 {
	 mSettingsfile = path;
	 this->mConnectType = (ConnectType)type;
	 this->mDataSource = (DataSourceNtrip)source;

 }
NtripDeal::NtripDeal(const std::string &path):mGpsDeal(NULL), NTRIPThread(NULL),
NTRIPIsConnected(false), StartNTRIPThreadIn(0), NTRIPConnectionAttempt(1),
NTRIPStreamRequiresGGA(false), NTRIPUseManualGGA(false),
NTRIPProtocol(1), NTRIPPort(0), NTRIPManualLat(41), NTRIPManualLon(-91),
NTRIPByteCount(0), mSerialPort(NULL), mCallBack(NULL), NTRIPCaster(""), NTRIPUsername(""),
NTRIPPassword(""), NTRIPMountPoint(""), GPSThread(NULL),
mSettingsfile(""), PreferredMountPoint("")
{
	NtripDeal();
	mSettingsfile = path;
}

NtripDeal::NtripDeal(const std::string &path, int type, int source):mGpsDeal(NULL), NTRIPThread(NULL),
NTRIPIsConnected(false), StartNTRIPThreadIn(0), NTRIPConnectionAttempt(1),
NTRIPStreamRequiresGGA(false), NTRIPUseManualGGA(false),
NTRIPProtocol(1), NTRIPPort(0), NTRIPManualLat(41), NTRIPManualLon(-91),
NTRIPByteCount(0), mSerialPort(NULL), mCallBack(NULL), NTRIPCaster(""), NTRIPUsername(""),
NTRIPPassword(""), NTRIPMountPoint(""), GPSThread(NULL),
mSettingsfile(""), PreferredMountPoint("")
{
	NtripDeal();
	initConnect(path, type, source);
}

NtripDeal::~NtripDeal()
{
}

void NtripDeal::connectNtrip(const std::string &ipcaster, int ipport, const std::string &node,const std::string &name,const std::string &pwd)
{
	NTRIPCaster = ipcaster;
	NTRIPPort = ipport;
	NTRIPMountPoint = node;
	NTRIPUsername = name;
	NTRIPPassword = pwd;

	NTRIPConnectionAttempt = 1;
	NTRIPShouldBeConnected = true;
	// 保存参数
	StartNTRIPThreadIn = 1;

	NTRIPProtocol = Ntrip;
}

void NtripDeal::connectTcp(const std::string &ipcaster, int ipport)
{
	NTRIPCaster = ipcaster;
	NTRIPPort = ipport;

	NTRIPConnectionAttempt = 1;
	NTRIPShouldBeConnected = true;
	// 保存参数
	StartNTRIPThreadIn = 1;

	NTRIPProtocol = Tcp;
}

void NtripDeal::disconnectNtrip()
{
	NTRIPShouldBeConnected = false;
	// 保存参数
	StopNTRIP();
}

void NtripDeal::startNtrip()
{
	if (NTRIPThread != NULL)
	{
		if (NTRIPThread->joinable())
		{
			//NtripCallback("disconnect", this->MsgCallBack);
			LOG(INFO) << "NTRIP thread is already running. Please disconnect first before trying to connect again." << std::endl;
			StopNTRIP();
		}
	}
	if (mConnectType == Ntrip)
	{
		if (NTRIPCaster.size() < 1)
		{
			NtripCallback(NtpError, "IP empty\n", callBack);
			return;
		}
		if (NTRIPPort == 0)
		{
			NtripCallback(NtpError, "port error:0\n", callBack);
			return;
		}
		if (NTRIPPort < 1 || NTRIPPort > 65535)
		{
			NtripCallback(NtpError, "port error:" + NTRIPPort, callBack);
			return;
		}
		if (NTRIPMountPoint == NTRIP_DEFAULT_NODE)
		{
			NTRIPMountPoint = "";
		}
		else
		{
			PreferredMountPoint = NTRIPMountPoint;
		}
		NTRIPStreamRequiresGGA = false;
		if (NTRIPStreamArray.size() > 1)
		{
			for (int i = 0; i < NTRIPStreamArray.at(1).size(); i++)
			{
				if (NTRIPStreamArray[0][i] == NTRIPMountPoint)
				{
					if (NTRIPStreamArray[1][i] == "1")
					{
						NTRIPStreamRequiresGGA = true;
					}
				}
			}
		}
	}
	NTRIPIsConnected = true;
	NTRIPThread = new std::thread([&] {NTRIPLoop(); });
	// NTRIPThread->join();
	if (mDataSource == Serialport) {
		mSerialPort = new SerialPortDataSourceTool("COM2", 115200);
		GPSThread = new std::thread(&NtripDeal::GPSLoop, this);
	}
}
void NtripDeal::StopNTRIP()
{
	StartNTRIPThreadIn = 0;
	NTRIPIsConnected = false;
	// NtripCallback("disconnect...", NtripDeal::MsgCallBack);
	// 等待线程结束
    PCL_SLEEP(0.1);
	if (NTRIPThread)
	{
		if (NTRIPThread->joinable())
		{
			//NTRIPThread->join();
            PCL_SLEEP(0.1);
			if (NTRIPThread) 
			{
				NTRIPThread->detach();
				delete NTRIPThread;
				NTRIPThread = NULL;
			}			
		}
	}
	NTRIPConnectionAttempt += 1;
	// NtripCallback("disconnected", &this->MsgCallBack);
	if (NTRIPConnectionAttempt > 1000) 
	{
		// 设置界面按钮可用
		NTRIPShouldBeConnected = false;
		// 保存设置
		LOG(WARNING) << "NTRIP Client is Disconnected, 10000 Failed Connection Attempts." << std::endl;
	}
	if (NTRIPShouldBeConnected) 
	{
		StartNTRIPThreadIn = 10;
		//PlayAudioAlert();
	}
	else
	{
		//  NtripCallback("connect", &this->MsgCallBack);
		// 界面启用
	}

}
void NtripDeal::NtripCallback(int code,const std::string &msg, NtripMsgCallback call)
{
	if (this->mCallBack)
	{
		this->mCallBack->MsgCallBack(code,msg);
	}
	else
	{
		call(code,msg);
	}
}
void NtripDeal::DiffCallBack(int code, const std::vector<char> &msg, int count, NtripMsgCallback call)
{
	if (this->mCallBack)
	{
        if(msg.size() > 0)
        {
            vector<unsigned char> uchars;
            uchars.resize(msg.size());
            memcpy(&uchars[0],&msg[0],msg.size());
            this->mCallBack->DiffCallBack(code,uchars,count);
        }
	}
	else
	{
		call(code,std::string(msg.data(),msg.size()));
	}
}

void NtripDeal::timeTick()
{
	if (StartNTRIPThreadIn > 0)
	{
		StartNTRIPThreadIn -= 1;
		if (StartNTRIPThreadIn == 0)
		{
			startNtrip();
		}
	}
}
std::string NtripDeal::generateRequestMessage()
{
	std::string msg;
	msg = "GET /" + NTRIPMountPoint + " HTTP/1.0" + vbCr + vbLf;
	msg += "User-Agent: NTRIP LefebureNTRIPClient/20131124" + vbCr + vbLf;
	msg += "Accept: */*" + vbCr + vbLf + "Connection: close" + vbCr + vbLf;
	if (NTRIPUsername.length() > 0) 
	{
		uint8 buf[1024] = {0};
		std::string values = NTRIPUsername + ":" + NTRIPPassword;
		base64_encode((uint8*)values.c_str(), values.size(), buf);
		std::string auth((char*)buf);
		//This line can be removed if no authorization is needed
		msg += "Authorization: Basic " + auth + vbCr + vbLf;
	}
	msg += vbCr + vbLf;
	return msg;
}
void NtripDeal::NTRIPLoop()
{
    PCL_SLEEP(1);
	switch (NTRIPProtocol)
	{
	case Ntrip: // NTRIP Protocol
	{
		bool NeedsToSendGGA = NTRIPStreamRequiresGGA;
		if (NeedsToSendGGA && !NTRIPUseManualGGA) 
		{
			if (MostRecentGGA == "")
			{
				NTRIPUpdateUIThread(-1, "", Nothing);
				while (true)
				{
					if (MostRecentGGA == "")
					{
						break;
					}
					if (!NTRIPIsConnected)
					{
						break;
						//NTRIPThread->join();
					}
                    PCL_SLEEP(0.1);
				}
			}
		}
		NTRIPUpdateUIThread(0, "", Nothing);
		SocketDataSourceTool sckt;
		int lcount = 97;
		if (!sckt.isConnect()) {
			// 连接服务器
            if (sckt.Connect(NTRIPPort,NTRIPCaster.c_str()))
			{
				std::string data = generateRequestMessage();
				NtripCallback(NtpDebug, data.c_str(), callBack);
				sckt.Send(data.c_str(), data.size());
			}
			else
			{
				NTRIPUpdateUIThread(100, "Server did not respond.", Nothing);
				//NTRIPThread->join();
			}
			//std::cout << "connect success" << std::endl;
		}
		else 
		{
			//std::cout << "connect fail" << std::endl;
		}
		NTRIPUpdateUIThread(1, "", Nothing);
		
        PCL_SLEEP(0.1);
		
		std::string responseData = "";
		char buffer[NtripBufferCount] = { 0 };
		for (int i = 0; i < 100; i++)
		{
            PCL_SLEEP(0.1);
			memset(buffer, 0, NtripBufferCount);
			int count = sckt.FetchNext(buffer, NtripBufferCount);
			if (count > 0)
			{
				responseData = std::string(buffer, count);
			}
			if (responseData.length() > 0 )
			{
				break;
			}
		}
		
		if (responseData.length() < 1) 
		{
			//NtripCallback(sckt.errorString().toStdString().c_str(), callBack);
			NTRIPUpdateUIThread(100, "Unknown Response.", Nothing);
		}
		else if (responseData.find("SOURCETABLE 200 OK") != responseData.npos)
		{
			for (int i = 0; i < 100; ++i) 
			{
                PCL_SLEEP(0.1);
				memset(buffer, 0, NtripBufferCount);
				int count = sckt.FetchNext(buffer, NtripBufferCount);
				if (count > 0)
				{
					responseData += std::string(buffer, count);
				}			
				
				if (responseData.find("ENDSOURCETABLE")!= responseData.npos)
				{
					break;
				}
			}	
			NTRIPUpdateUIThread(101, responseData, Nothing);
			sckt.Close();
			NTRIPUpdateUIThread(100, "Downloaded Source Table", Nothing);
			//NTRIPThread->join();
		}
		else if (responseData.find("401 Unauthorized") != responseData.npos)
		{
			sckt.Close();
			NTRIPUpdateUIThread(100, "Invalid Username or Password.", Nothing);
			//NTRIPThread->join();
		}
		else if (responseData.find("ICY 200 OK") != responseData.npos)
		{
			NTRIPUpdateUIThread(2, "", Nothing);
			int DataNotReceivedFor = 0;
			bool KeepRuning = true;
			while (KeepRuning)
			{
				memset(buffer, 0, NtripBufferCount);
				int count = 0;
				count = sckt.FetchNext(buffer, NtripBufferCount);
				if (count == 0||count==-1)
				{
					DataNotReceivedFor += 1;
					if (DataNotReceivedFor > 300)
					{
						KeepRuning = false;
						NTRIPUpdateUIThread(100, "Connection Timed Out.", Nothing);
						break;
						//NTRIPThread->join();
					}
				}
				else
				{
					DataNotReceivedFor = 0;
					/*memset(buffer, 0, NtripBufferCount);
					int count = sckt.FetchNext(buffer, NtripBufferCount);*/
					std::vector<char> data;
					data.assign(buffer, &buffer[count]);
					NTRIPUpdateUIThread(3, "", data);
				}
				lcount += 1;
				if (lcount == 100)
				{
					if (NeedsToSendGGA)
					{
						std::string TheGGA;
						if (NTRIPUseManualGGA)
						{
							TheGGA = mGpsDeal->GenerateGPGGAcode();
						}
						else
						{
							TheGGA = NtripDeal::MostRecentGGA;
							//std::cout << "test3:"<<NtripDeal::MostRecentGGA.c_str() << std::endl;
						}
						std::string namedata = TheGGA + vbCrLf;
						try
						{
							sckt.Send(namedata.c_str(), namedata.size());
						}
						catch (const std::exception&ex)
						{
							NTRIPUpdateUIThread(100, "Error: " + std::string(ex.what()), Nothing);
						}
					}
					lcount = 0;
				}
				if (!NTRIPIsConnected)
				{
					sckt.Close();
					KeepRuning = false;
					NTRIPUpdateUIThread(100, "", Nothing);
					//NTRIPThread->join();
					KeepRuning = false;
				}
                PCL_SLEEP(0.1);
			}
		}
		else
		{
			sckt.Close();
			if (responseData.length() > 0)
			{
				NTRIPUpdateUIThread(100, "No Response.", Nothing);
			}
			else
			{
				NTRIPUpdateUIThread(100, "Unknown Response.", Nothing);
			}

			break;
			//NTRIPThread->join();
		}
		break;
	}
	case Tcp:
	{
		/*NTRIPUpdateUIThread(0, "", Nothing);
		QTcpSocket *sckt = new QTcpSocket();
		try
		{
			sckt->connectToHost(NTRIPCaster.c_str(), NTRIPPort);
		}
		catch (const std::exception&)
		{
			NTRIPUpdateUIThread(100, "Server did not respond.", Nothing);
			NTRIPThread->join();
		}
		NTRIPUpdateUIThread(1, "", Nothing);
		int DataNotReceivedFor = 0;
		bool KeepRuning = true;
		while (KeepRuning)
		{
			QByteArray buffer = sckt->readAll();
			if (buffer.size() == 0)
			{
				DataNotReceivedFor += 1;
				if (DataNotReceivedFor > 300)
				{
					KeepRuning = false;
					NTRIPUpdateUIThread(100, "Connection Timed Out.", Nothing);
					NTRIPThread->join();
				}
			}
			else
			{
				DataNotReceivedFor = 0;
				NTRIPUpdateUIThread(3, Nothing, buffer.data());
			}
			if (!NTRIPIsConnected)
			{
				sckt->abort();
				KeepRuning = false;
				NTRIPUpdateUIThread(100, "", Nothing);
				NTRIPThread->join();
			}
			Sleep(100);
		}*/
		NTRIPUpdateUIThread(0, "", Nothing);
		SocketDataSourceTool sckt;
		if (!sckt.isConnect()) {
			// 连接服务器
            if (sckt.Connect(NTRIPPort,NTRIPCaster.c_str()))
			{
				
			}
			else
			{
				NTRIPUpdateUIThread(100, "Server did not respond.", Nothing);
				NTRIPThread->detach();
				delete NTRIPThread;
				NTRIPThread = NULL;
			}
		}
		else
		{
			NTRIPThread->detach();
			delete NTRIPThread;
			NTRIPThread = NULL;
		}
		NTRIPUpdateUIThread(1, "", Nothing);

        PCL_SLEEP(0.1);

		int DataNotReceivedFor = 0;
		bool KeepRuning = true;
		while (KeepRuning) {
			char buffer[NtripBufferCount] = { 0 };
            memset(buffer, 0, NtripBufferCount);
			int count = sckt.FetchNext(buffer, NtripBufferCount);
			if (count == 0 || count == -1)
			{
				DataNotReceivedFor += 1;
				if (DataNotReceivedFor > 300)
				{
					KeepRuning = false;
					NTRIPUpdateUIThread(100, "Connection Timed Out.", Nothing);
					break;
					//NTRIPThread->join();
				}
			}
			else
			{
				DataNotReceivedFor = 0;
				/*memset(buffer, 0, NtripBufferCount);
				int count = sckt.FetchNext(buffer, NtripBufferCount);*/
				std::vector<char> data;
				data.assign(buffer, &buffer[count]);
				NTRIPUpdateUIThread(3, "", data);
			}
			if (!NTRIPIsConnected)
			{
				sckt.Close();
				KeepRuning = false;
				NTRIPUpdateUIThread(100, "", Nothing);
				NTRIPThread->detach();
				delete NTRIPThread;
				NTRIPThread = NULL;
			}
            PCL_SLEEP(0.1);
		}
		break;
	}
	default:
		break;
	}
}

void NtripDeal::NTRIPUpdateUIThread(int Item,const std::string &Value,const std::vector<char> &myBytes)
{
	switch (Item)
	{
	case -1:
	{
		NtripCallback(NtpInfo,"Waiting for NMEA GGA data...", callBack);
		break;
	}
	case 0:
	{
		NtripCallback(NtpInfo, "Connecting...", callBack);
		if (NTRIPConnectionAttempt > 1)
		{
			NtripCallback(NtpWarrnning, " Attempt " + NTRIPConnectionAttempt, callBack);
			LogEvent("NTRIP Client is attempting to reconnect, Attempt " + NTRIPConnectionAttempt);
		}
		else
		{
			LogEvent("NTRIP Client is attempting to connect.");
			if (NTRIPStreamRequiresGGA && NTRIPUseManualGGA)
			{
                std::ostringstream stream;
                stream << "NTRIP is using a simulated location of ";
                stream << NTRIPManualLat;
                stream << ",";
                stream <<NTRIPManualLon;
                LogEvent(stream.str());
			}
		}
		break;
	}
	case 1:
	{
		NtripCallback(NtpInfo,"Connected, Requesting Data...", callBack);
		NTRIPByteCount = 0;
		break;
	}
	case 2:
	{
		NtripCallback(NtpInfo,"Connected, Waiting for Data...", callBack);
		// 更新进度条
		LogEvent("NTRIP Client is Connected, Waiting for Data.");
		break;
	}
	case 3:
	{
		if (mSerialPort) 
		{
			if (!mSerialPort->IsEof()) 
			{
				mSerialPort->Send(&myBytes.front(), myBytes.size());
			}
		}
		else
		{
			// 由外部通讯器操作差分数据发送
			DiffCallBack(NtpDiff, myBytes, myBytes.size(), callBack);
		}
		if(NTRIPByteCount = 0)
		{
			LogEvent("NTRIP Client is receiving data.");
		}

		NTRIPByteCount += myBytes.size();		
        std::ostringstream stream;
        stream << "Connected, ";
        stream << NTRIPByteCount;
        stream << " bytes received.";
        NtripCallback(NtpInfo, stream.str(), callBack);
		// 更新进度条
		break;
	}
	case 100:
	{
		if (Value == "Invalid Username or Password.")
		{
			NTRIPShouldBeConnected = false;
		}
		else if (Value == "Unknown Response.")
		{
			NTRIPShouldBeConnected = false;
		}
		else if (Value == "")
		{
			LogEvent("NTRIP Client is Disconnected.");
		}
		else
		{
			LogEvent("NTRIP Client is Disconnected, " + Value);
		}
		StopNTRIP();
		NtripCallback(NtpError, Value, callBack);
		break;
	}
	case 101:
	{
		LogEvent("NTRIP Client downloaded the Source Table.");
		NTRIPShouldBeConnected = false;
		StopNTRIP();
		ParseSourceTable(Value);
		break;
	}
	case 201:
	{
		NtripCallback(NtpMount,Value.c_str(), callBack);
		break;
	}
	default:
		break;
	}
}

void NtripDeal::LoadSettingsFile()
{
	// 从配置文件中读取
	ifstream _file(mSettingsfile);
	string s;
	while (getline(_file, s)) {
		s.c_str();
		string key = s.substr(0, s.find('='));
		string value = s.substr(s.find('=')+1);
		if (key == "serial should be connected"&&value == "Yes") {
			//SerialShouldBeConnected = True;
		}
		if (key == "serial port number") {

		}
		else if (key == "serial port speed") {

		}
		else if (key == "serial port data bits") {

		}
		else if (key == "serial port stop bits") {

		}
		else if (key == "protocol") {
			if (value == "RawTCPIP")
				NTRIPProtocol = 0;
			else
				NTRIPProtocol = 1;
		}
		else if (key == "ntrip should be connected" && value == "Yes")
			NTRIPShouldBeConnected = true;
		else if (key == "ntrip use manual gga" && value == "Yes")
			NTRIPUseManualGGA = true;
		else if (key == "ntrip manual latitude")
		{
			if (IsNumeric(value)) {
				int inlat = atoi(value.c_str());
				if (inlat > -90 && inlat < 90)
					NTRIPManualLat = inlat;
				else
					LogEvent("Specified NTRIP Manual Latitude should be between -90 and 90.");
			}
			else
				LogEvent("Specified NTRIP Manual Latitude should be numeric.");
		}
		else if (key == "ntrip manual longitude")
		{
			if (IsNumeric(value)) {
				int inlon = atoi(value.c_str());
				if (inlon > -90 && inlon < 90)
					NTRIPManualLat = inlon;
				else
					LogEvent("Specified NTRIP Manual Longitude should be between -90 and 90.");
			}
			else
				LogEvent("Specified NTRIP Manual Longitude should be numeric.");
		}
		else if (key == "audio alert file"&&value == "Yes") {
			//WriteEventsToFile = True
		}
		else if (key == "write nmea to file"&&value == "Yes") {
			//WriteNMEAToFile = True
		}
		else if (key == "display center") {
			//GPS.Disp2 = LCase(value)
		}
		else if (key == "display right") {
			//GPS.Disp3 = LCase(value)
		}
		else if (key == "check for updates interval") {
			if (value == "weekly") {
				//CheckForUpdateDays = 7
			}
			else {
				//CheckForUpdateDays = 0
			}
		}
		else if (key == "last checked for updates") {
			//If IsDate(value) Then
			//	LastCheckedForUpdates = CDate(value)
		}
		else if (key == "receiver type") {
			if (value == "novatel") {
				//ReceiveType = 1
			}
			else {
				//ReceiveType = 0;
			}
		}
		else if (key == "receiver correction format") {
			if (value == "rtcm") {
				//ReceiverCorrDataType = "RTCM"
			}
			else if (value == "rtcmv3") {
				//ReceiverCorrDataType = "RTCMV3"
			}
			else if (value == "cmr") {
				//ReceiverCorrDataType = "CMR"
			}
			else if (value == "rtca") {
				//ReceiverCorrDataType = "RTCA"
			}
			else if (value == "omnistar") {
				//ReceiverCorrDataType = "OMNISTAR"
			}
			else {
				//ReceiverCorrDataType = "NOVATEL"
			}
		}
		else if (key == "receiver message rate") {
			if (value == "5") {
				//ReceiverMessageRate = 5
			}
			else if (value == "10") {
				//ReceiverMessageRate = 10
			}
			else {
				//ReceiverMessageRate = 1
			}
		}
		else if (key == "NTRIP Caster") {
			NTRIPCaster = value;
		}
		else if (key == "NTRIP Caster Port") {
			NTRIPPort = atoi(value.c_str());
		}
		else if (key == "NTRIP Username") {
			NTRIPUsername = value;
		}
		else if (key == "NTRIP Password") {
			NTRIPPassword = value;
		}
		else if (key == "NTRIP MountPoint") {
			NTRIPMountPoint = value;
		}
		else if (key == "NTRIP MountPointList") {
			NTRIPStreamArray.clear();
			NTRIPStreamArray.push_back(std::vector<std::string>());
			NTRIPStreamArray.push_back(std::vector<std::string>());
			std::vector<std::string> list;
			MyString::split(value, ";", &list);
			for (int i = 0; i < list.size() - 1; i=i+2) {
				NTRIPStreamArray.at(0).push_back(list.at(i));
				NTRIPStreamArray.at(1).push_back(list.at(i+1));
			}
		}
		else {
			//If Not SettingsArray(0, i) = "" Then
			//LogEvent("Just FYI, the """ & SettingsArray(0, i) & """ key in the settings file isn't valid, so it was skipped.")
		}
	}
}

void NtripDeal::SaveSetting()
{
	ofstream _file(mSettingsfile, fstream::out);
	if (_file.fail()) 
	{
	}
	_file << "protocol=" << (NTRIPProtocol == 0 ? "RawTCPIP" : "NTRIP") << endl;
	_file << "ntrip should be connected=" << (NTRIPShouldBeConnected ? "Yes" : "No") << endl;
	_file << "ntrip use manual gga=" << (NTRIPUseManualGGA ? "Yes" : "No") << endl;
    _file << "ntrip manual latitude=" << NTRIPManualLat << endl;
    _file << "ntrip manual longitude=" << NTRIPManualLon << endl;
	_file << "NTRIP Caster=" << NTRIPCaster << endl;
    _file << "NTRIP Caster Port=" << NTRIPPort << endl;
	_file << "NTRIP Username=" << NTRIPUsername << endl;
	_file << "NTRIP Password=" << NTRIPPassword << endl;
	_file << "NTRIP MountPoint=" << NTRIPMountPoint << endl;
	_file << "NTRIP MountPointList=";
	if (NTRIPStreamArray.size() > 0) {
		for (int i = 0; i < NTRIPStreamArray[0].size(); i++) {
			_file << NTRIPStreamArray[0][i] << ";" << NTRIPStreamArray[1][i] << ";";
		}
	}
	_file << endl;
	_file.close();
}

bool NtripDeal::IsNumeric(std::string str)
{
	for (int i = 0; i < str.length(); i++) {
		if (!isdigit(str[i]))
			return false;
	}
	return true;
}

void NtripDeal::init()
{
	LoadSettingsFile();
	if (NTRIPShouldBeConnected)
	{
		StartNTRIPThreadIn = 1;
	}
}

void NtripDeal::LogEvent(const std::string &msg)
{
	LOG(INFO) << msg << std::endl;
}
void NtripDeal::ParseSourceTable(const std::string &table)
{
	std::vector<std::string> mountPointList;
	//mountPointList.push_back(defaultNode);
	NTRIPStreamArray.clear();
	NTRIPStreamArray.push_back(std::vector<std::string>());
	NTRIPStreamArray.push_back(std::vector<std::string>());
	int StreamCount = -1;
	// 界面增加默认的"Download Source Table"，并设置为选中
	std::vector<std::string> lines;
	MyString::split(table, vbCrLf, &lines);
	for (int i = 0; i < lines.size(); i++)
	{
		std::vector<std::string> fields;
		MyString::split(lines.at(i), ";", &fields);
		if (fields.size() > 4) 
		{
			std::string first = fields.at(0);
            transform(first.begin(), first.end(), first.begin(), ::tolower);
			if (first.compare("str") == 0)
			{
				mountPointList.push_back(fields.at(1));
				StreamCount += 1;
				NTRIPStreamArray.at(0).push_back(fields.at(1));
				NTRIPStreamArray.at(1).push_back(fields.at(11));
			}
		}
	}

	// 回调挂载点列表给界面
	NTRIPUpdateUIThread(201, MyString::vector_string_to_string(mountPointList, ";"), Nothing);
}
void NtripDeal::ReceiveNMEA(int type, const std::string &nmea, bool isManual)
{
	// 0 GGA
	if (type == 0)
	{
		NTRIPUseManualGGA = isManual;
		if (isManual)
		{
			// 手动构造GGA
			SendSerialLineToUIThread(nmea);
		}
		else
		{
			// 直接使用GGA
			SendSerialLineToUIThread(nmea);
		}
		
	}
}
void NtripDeal::SendSerialLineToUIThread(const std::string &nmea)
{
	mGpsDeal->ProcessNMEAdata(nmea);
}

void NtripDeal::GPSLoop()
{
    if (!mSerialPort->IsEof())
    {
		char* buffer = nullptr;
		mSerialPort->FetchNext(buffer, 1024);
		ReceiveNMEA(0, buffer, false);
	}
	else {
        PCL_SLEEP(0.01);
	}
}

bool NtripDeal::hasSourceTable()
{
	if (NTRIPStreamArray.size()>0&&NTRIPStreamArray[0].size() > 0)
		return true;
	else
		return false;
}
